#include <nice2d/application.h>
#include <nice2d/deserializerfactory.h>
#include <nice2d/widgets/directionbutton.h>
#include <nice2d/widgets/desktop.h>

IMPLEMENT_OBJECT(DirectionButtonStyle, ControlStyle)

DirectionButtonStyle::DirectionButtonStyle():
    normalButtonColor(0x33, 0x66, 0x99),
    hoverButtonColor(0x66, 0x66, 0x99),
    pressedButtonColor(0x99, 0x66, 0x99)
{
}

PTree DirectionButtonStyle::serialize()
{
    PTree node;
    SERIALIZE_BASE_OBJECT(node, ControlStyle)
    SERIALIZE_SIMPLE_OBJECT(node, normalButtonColor)
    SERIALIZE_SIMPLE_OBJECT(node, hoverButtonColor)
    SERIALIZE_SIMPLE_OBJECT(node, pressedButtonColor)
    return node;
}

void DirectionButtonStyle::deserialize(const PTree &node)
{
    DESERIALIZE_BASE_OBJECT(node, ControlStyle)
    DESERIALIZE_SIMPLE_OBJECT(node, normalButtonColor)
    DESERIALIZE_SIMPLE_OBJECT(node, hoverButtonColor)
    DESERIALIZE_SIMPLE_OBJECT(node, pressedButtonColor)
}

void DirectionButtonStyle::sync()
{
}

IMPLEMENT_OBJECT(DirectionButton, BasicButton)

#define DEFAULT_DIRECTION_BUTTON_SIZE 18

class DirectionButtonData
{
public:
    DirectionButton *button = nullptr;
    Direction direction;
    sf::ConvexShape shape[2];

    void adjust()
    {
        int padding = button->getPadding();
        int left = button->getPosition().x;
        int top = button->getPosition().y;
        int right = left + button->getSize().x;
        int bottom = top + button->getSize().y;

        if (direction == Direction::Direction_Down) {
            shape[0].setPoint(0, sf::Vector2f(left + padding, top + padding));
            shape[0].setPoint(1, sf::Vector2f(right - padding, top + padding));
            shape[0].setPoint(2, sf::Vector2f(left + button->getSize().x * 0.5f, bottom - padding));
        } else if (direction == Direction::Direction_Up) {
            shape[0].setPoint(0, sf::Vector2f(left + padding, bottom - padding));
            shape[0].setPoint(1, sf::Vector2f(right - padding, bottom - padding));
            shape[0].setPoint(2, sf::Vector2f(left + button->getSize().x * 0.5f, top + padding));
        } else if (direction == Direction::Direction_Left) {
            shape[0].setPoint(0, sf::Vector2f(right - padding, bottom - padding));
            shape[0].setPoint(1, sf::Vector2f(right - padding, top + padding));
            shape[0].setPoint(2, sf::Vector2f(left + padding, top + button->getSize().y * 0.5f));
        } else if (direction == Direction::Direction_Right) {
            shape[0].setPoint(0, sf::Vector2f(left + padding, bottom - padding));
            shape[0].setPoint(1, sf::Vector2f(left + padding, top + padding));
            shape[0].setPoint(2, sf::Vector2f(right - padding, top + button->getSize().y * 0.5f));
        }

        for (int i = 0; i < 3; i++) {
            auto point = shape[0].getPoint(i);
            shape[1].setPoint(i, sf::Vector2f(point.x + 1.0f, point.y + 1.0f));
        }
    }
};

DirectionButton::DirectionButton(Direction direction):
    data(new DirectionButtonData())
{
    data->button = this;
    data->direction = direction;
    data->shape[0] = sf::ConvexShape(3);
    data->shape[1] = sf::ConvexShape(3);

    auto desktop = GET_COMPONENT(Application::getInstance(), Desktop);
    setControlStyle(desktop->getControlStyle("DirectionButton"));

    setSize(DEFAULT_DIRECTION_BUTTON_SIZE, DEFAULT_DIRECTION_BUTTON_SIZE);
}

DirectionButton::~DirectionButton()
{
}

Direction DirectionButton::getDirection() const
{
    return data->direction;
}

sf::Vector2i DirectionButton::getHintSize()const
{
    return sf::Vector2i(DEFAULT_DIRECTION_BUTTON_SIZE, DEFAULT_DIRECTION_BUTTON_SIZE);
}

void DirectionButton::onDraw(sf::RenderTarget &target, sf::RenderStates states) const
{
    BasicButton::onDraw(target, states);

    if (getButtonState() == BasicButtonState_Down)
        target.draw(data->shape[1], states);
    else
        target.draw(data->shape[0], states);
}

void DirectionButton::onPositionChanged()
{
    data->adjust();
}

void DirectionButton::onSizeChanged()
{
    data->adjust();
}

void DirectionButton::onStyleChanged()
{
    BasicButton::onStyleChanged();
    auto style = getTemplateStyle<DirectionButtonStyle>();
    if (getButtonState() == BasicButtonState_Normal) {
        data->shape[0].setFillColor(style->normalButtonColor);
        data->shape[1].setFillColor(style->normalButtonColor);
    } else if (getButtonState() == BasicButtonState_Hover) {
        data->shape[0].setFillColor(style->hoverButtonColor);
        data->shape[1].setFillColor(style->hoverButtonColor);
    } else {
        data->shape[0].setFillColor(style->pressedButtonColor);
        data->shape[1].setFillColor(style->pressedButtonColor);
    }
}

DECL_DESERIALIZER_FACTORY_IMPL(DirectionButtonStyle)
